#include "test_list.h"


#ifdef TEST_ITERATOR_RECURSIVE

#include "libden/iterator.h"

#include <string>
#include <list>

#if defined(__GNUC__) || defined(__MINGW__) || defined(__MINGW32__)
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Weffc++"
    #pragma GCC diagnostic ignored "-Wconversion-null"
#endif

#define TEST_CASE_NAME IteratorRecursive

#define TEST_SPEC(n) BasicFunctional##_##n


#define TEST_ITERATOR_RECURSIVE_000
#define TEST_ITERATOR_RECURSIVE_001
#define TEST_ITERATOR_RECURSIVE_002
#define TEST_ITERATOR_RECURSIVE_003
#define TEST_ITERATOR_RECURSIVE_004
#define TEST_ITERATOR_RECURSIVE_005
#define TEST_ITERATOR_RECURSIVE_006
#define TEST_ITERATOR_RECURSIVE_007
#define TEST_ITERATOR_RECURSIVE_008
#define TEST_ITERATOR_RECURSIVE_009
#define TEST_ITERATOR_RECURSIVE_010
#define TEST_ITERATOR_RECURSIVE_011
#define TEST_ITERATOR_RECURSIVE_012
#define TEST_ITERATOR_RECURSIVE_013
#define TEST_ITERATOR_RECURSIVE_014
#define TEST_ITERATOR_RECURSIVE_015
#define TEST_ITERATOR_RECURSIVE_016
#define TEST_ITERATOR_RECURSIVE_017
#define TEST_ITERATOR_RECURSIVE_018
#define TEST_ITERATOR_RECURSIVE_019
#define TEST_ITERATOR_RECURSIVE_020
#define TEST_ITERATOR_RECURSIVE_021
#define TEST_ITERATOR_RECURSIVE_022
#define TEST_ITERATOR_RECURSIVE_023
#define TEST_ITERATOR_RECURSIVE_024
#define TEST_ITERATOR_RECURSIVE_025
#define TEST_ITERATOR_RECURSIVE_026
#define TEST_ITERATOR_RECURSIVE_027
#define TEST_ITERATOR_RECURSIVE_028
#define TEST_ITERATOR_RECURSIVE_029
#define TEST_ITERATOR_RECURSIVE_030
#define TEST_ITERATOR_RECURSIVE_031
#define TEST_ITERATOR_RECURSIVE_032

//------------------------------------------------------------------------------------------------------//

namespace{

    typedef ::std::string
        Str;
    typedef Str::value_type
        Ch;

    Str Deep(const size_t d,const Ch ch=' '){ return Str(d*2,ch); }

    struct Sample: public std::iterator<std::bidirectional_iterator_tag , Sample>
    {
        typedef list<Sample> 
            List;

        typedef IteratorWrapper<List, Way::begin>
            iterator;
        typedef IteratorWrapper<List, Way::cbegin>
            const_iterator;
        typedef IteratorWrapper<List, Way::rbegin>
            reverse_iterator;
        typedef IteratorWrapper<List, Way::crbegin>
            const_reverse_iterator;
       

        Sample(const size_t n, Sample* parent= nullptr)
            :mNum(n)
            ,mList()
            ,mParent(parent)
        {}

        Sample& Add(const size_t n)
        {
            mList.emplace_back(n, this);
            return *this;
        }
        Sample& Open(const size_t n)
        {
            mList.emplace_back(n,this);
            return mList.back();
        }
        Sample& Close()
        {
            if(mParent)
                return *mParent;
            return *this;
        }

        Str GetName()const 
        {
            return "block-" + ::std::to_string(mNum);
        }

        void View()const { View(0); }

        const Sample& View(const size_t d)const
        {
            std::cout<< Deep(d) << "block-"<< mNum <<'\n';
            if(!mList.empty())
                for(const auto& f: mList)
                    f.View(d+1);
            return *this;
        }

        iterator               begin()          { return iterator(mList, mList.begin());                 }
        iterator               end()            { return iterator(mList, mList.end());                   }
        const_iterator         begin()const     { return const_iterator(mList, mList.begin());           }
        const_iterator         end()const       { return const_iterator(mList, mList.end());             }

        const_iterator         cbegin()const    { return const_iterator(mList, mList.cbegin());          }
        const_iterator         cend()const      { return const_iterator(mList, mList.cend());            }

        reverse_iterator       rbegin()         { return reverse_iterator(mList, mList.rbegin());        }
        reverse_iterator       rend()           { return reverse_iterator(mList, mList.rend());          }
        const_reverse_iterator rbegin()const    { return const_reverse_iterator(mList, mList.rbegin());  }
        const_reverse_iterator rend()const      { return const_reverse_iterator(mList, mList.rend());    }

        const_reverse_iterator crbegin()const   { return const_reverse_iterator(mList, mList.crbegin()); }
        const_reverse_iterator crend()const     { return const_reverse_iterator(mList, mList.crend());   }

        size_t  mNum;
        List    mList;
        Sample* mParent;
    };
}//namespace
//------------------------------------------------------------------------------------------------------//

#ifdef TEST_ITERATOR_RECURSIVE_000
TEST(TEST_CASE_NAME, TEST_SPEC(000))
{
    #if 0
    block1
     |---block2
     |---block3
     |---block4
     |    |---block5
     |     `---block6
     |---block7
     |---block8
     |---block9
     |    `---block10
     |         `---block11
     `---block12

    #endif

    Sample sample(1);
    sample
        .Add(2)
        .Add(3)
        .Open(4)
            .Add(5)
            .Add(6)
        .Close()
        .Add(7)
        .Add(8)
        .Open(9)
            .Open(10)
                .Add(11)
            .Close()
        .Close()
        .Add(12)
    .Close()
    .View();

    typedef IteratorRecurcive< Sample::iterator >
        Recursive;
    Recursive it(sample);
    cout<<"========2-12============\n";
    while(it)
        cout<< it->GetName()<<'\n',
        ++it;

    it = sample;
    ASSERT_TRUE(  it->GetName()=="block-2" ); ++it;
    ASSERT_TRUE(  it->GetName()=="block-3" ); ++it;
    ASSERT_TRUE(  it->GetName()=="block-4" ); ++it;
    ASSERT_TRUE(  it->GetName()=="block-5" ); ++it;
    ASSERT_TRUE(  it->GetName()=="block-6" ); ++it;
    ASSERT_TRUE(  it->GetName()=="block-7" ); ++it;
    ASSERT_TRUE(  it->GetName()=="block-8" ); ++it;
    ASSERT_TRUE(  it->GetName()=="block-9" ); ++it;
    ASSERT_TRUE(  it->GetName()=="block-10"); ++it;
    ASSERT_TRUE(  it->GetName()=="block-11"); ++it;
    ASSERT_TRUE(  it->GetName()=="block-12"); ++it;
    ASSERT_TRUE(  it.End() ); 

    cout<< "[last] = " << it.GetLast()->GetName()<< endl;
    ASSERT_TRUE( it.GetLast()->GetName()=="block-12" );

    --it; ASSERT_TRUE(  it->GetName()=="block-12"); 
    --it; ASSERT_TRUE(  it->GetName()=="block-11"); 
    --it; ASSERT_TRUE(  it->GetName()=="block-10"); 
    --it; ASSERT_TRUE(  it->GetName()=="block-9" ); 
    --it; ASSERT_TRUE(  it->GetName()=="block-8" ); 
    --it; ASSERT_TRUE(  it->GetName()=="block-7" ); 
    --it; ASSERT_TRUE(  it->GetName()=="block-6" ); 
    --it; ASSERT_TRUE(  it->GetName()=="block-5" ); 
    --it; ASSERT_TRUE(  it->GetName()=="block-4" ); 
    --it; ASSERT_TRUE(  it->GetName()=="block-3" ); 
    --it; ASSERT_TRUE(  it->GetName()=="block-2" ); 
    ASSERT_TRUE( it.Beg() ); --it;
    ASSERT_TRUE( it.GetLast()->GetName()=="block-2" );

    ++it; ASSERT_TRUE(  it->GetName()=="block-2" ); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-3" ); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-4" ); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-5" ); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-6" ); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-7" ); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-8" ); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-9" ); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-10"); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-11"); 
    ++it; ASSERT_TRUE(  it->GetName()=="block-12"); 
    ++it; ASSERT_TRUE(  it.End() ); 
    cout<< "[last] = " << it.GetLast()->GetName()<< endl;
    ASSERT_TRUE( it.GetLast()->GetName()=="block-12" );

    cout<<"========12-2============\n";
    it = sample.end();
    while(--it)
        cout<< it->GetName()<<'\n';
}
#endif // TEST_ITERATOR_RECURSIVE_000

#ifdef TEST_ITERATOR_RECURSIVE_001
TEST(TEST_CASE_NAME, TEST_SPEC(001))
{
    Sample sample(1);
    sample
         .Add(2)
    .Close()
    .View();

    typedef IteratorRecurcive< Sample::iterator >
        Recursive;

    Recursive it(sample);
    Recursive it2(it);
    ASSERT_TRUE(  it2.Beg() ); 
    --it2;
    ASSERT_TRUE(  it2.Empty() ); 
}
#endif // TEST_ITERATOR_RECURSIVE_001

#ifdef TEST_ITERATOR_RECURSIVE_002
TEST(TEST_CASE_NAME, TEST_SPEC(002))
{
#if 0
    block1
        |---block2
        |---block3
        |---block4
        |    |---block5
        |     `---block6
        |---block7
        |---block8
        |---block9
        |    `---block10
        |         `---block11
        `---block12
#endif

    Sample sample(1);
    sample
        .Add(2)
        .Add(3)
        .Open(4)
            .Add(5)
            .Add(6)
        .Close()
        .Add(7)
        .Add(8)
        .Open(9)
            .Open(10)
                .Add(11)
            .Close()
        .Close()
        .Add(12)
    .Close()
    .View();

    typedef IteratorRecurcive< Sample::reverse_iterator >
        Recursive;
    Recursive it(sample);

    cout<<"========12-2============\n";
    while(it)
        cout<< it->GetName()<<'\n',
        ++it;

   it = sample;
         ASSERT_TRUE(it->GetName()=="block-12");
   ++it; ASSERT_TRUE(it->GetName()=="block-11");
   ++it; ASSERT_TRUE(it->GetName()=="block-10");
   ++it; ASSERT_TRUE(it->GetName()=="block-9" );
   ++it; ASSERT_TRUE(it->GetName()=="block-8" );
   ++it; ASSERT_TRUE(it->GetName()=="block-7" );
   ++it; ASSERT_TRUE(it->GetName()=="block-6" );
   ++it; ASSERT_TRUE(it->GetName()=="block-5" );
   ++it; ASSERT_TRUE(it->GetName()=="block-4" );
   ++it; ASSERT_TRUE(it->GetName()=="block-3" );
   ++it; ASSERT_TRUE(it->GetName()=="block-2" );
   ++it; ASSERT_TRUE(it.End());
   ASSERT_TRUE( it.GetLast()->GetName()=="block-2" );
   cout<<"===============================\n";
 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-2" ); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-3" ); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-4" ); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-5" ); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-6" ); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-7" ); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-8" ); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-9" ); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-10"); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-11"); 
   --it; cout<< "[====] "<< it->GetName()<<endl; ASSERT_TRUE(it->GetName()=="block-12"); 
   --it; ASSERT_TRUE(it.End() );
   ASSERT_TRUE( it.GetLast()->GetName()=="block-12" );

   ++it; ASSERT_TRUE(it->GetName()=="block-12");
   ++it; ASSERT_TRUE(it->GetName()=="block-11");
   ++it; ASSERT_TRUE(it->GetName()=="block-10");
   ++it; ASSERT_TRUE(it->GetName()=="block-9" );
   ++it; ASSERT_TRUE(it->GetName()=="block-8" );
   ++it; ASSERT_TRUE(it->GetName()=="block-7" );
   ++it; ASSERT_TRUE(it->GetName()=="block-6" );
   ++it; ASSERT_TRUE(it->GetName()=="block-5" );
   ++it; ASSERT_TRUE(it->GetName()=="block-4" );
   ++it; ASSERT_TRUE(it->GetName()=="block-3" );
   ++it; ASSERT_TRUE(it->GetName()=="block-2" );
   ++it; ASSERT_TRUE(it.End());
   ASSERT_TRUE( it.GetLast()->GetName()=="block-2" );
   cout<<"===============================\n";


   cout<<"========12-2============\n";
   it = sample.rend();
   while(--it)
       cout<< it->GetName()<<'\n';

}
#endif // TEST_ITERATOR_RECURSIVE_002

#ifdef TEST_ITERATOR_RECURSIVE_003
#endif // TEST_ITERATOR_RECURSIVE_003

#ifdef TEST_ITERATOR_RECURSIVE_004
#endif // TEST_ITERATOR_RECURSIVE_004

#ifdef TEST_ITERATOR_RECURSIVE_005
#endif // TEST_ITERATOR_RECURSIVE_005

#ifdef TEST_ITERATOR_RECURSIVE_006
#endif // TEST_ITERATOR_RECURSIVE_006

#ifdef TEST_ITERATOR_RECURSIVE_007
#endif // TEST_ITERATOR_RECURSIVE_007

#ifdef TEST_ITERATOR_RECURSIVE_008
#endif // TEST_ITERATOR_RECURSIVE_008

#ifdef TEST_ITERATOR_RECURSIVE_009
#endif // TEST_ITERATOR_RECURSIVE_009

#ifdef TEST_ITERATOR_RECURSIVE_010
#endif // TEST_ITERATOR_RECURSIVE_010

#ifdef TEST_ITERATOR_RECURSIVE_011
#endif // TEST_ITERATOR_RECURSIVE_011

#ifdef TEST_ITERATOR_RECURSIVE_012
#endif // TEST_ITERATOR_RECURSIVE_012

#ifdef TEST_ITERATOR_RECURSIVE_013
#endif // TEST_ITERATOR_RECURSIVE_013

#ifdef TEST_ITERATOR_RECURSIVE_014
#endif // TEST_ITERATOR_RECURSIVE_014

#ifdef TEST_ITERATOR_RECURSIVE_015
#endif // TEST_ITERATOR_RECURSIVE_015

#ifdef TEST_ITERATOR_RECURSIVE_016
#endif // TEST_ITERATOR_RECURSIVE_016

#ifdef TEST_ITERATOR_RECURSIVE_017
#endif // TEST_ITERATOR_RECURSIVE_017

#ifdef TEST_ITERATOR_RECURSIVE_018
#endif // TEST_ITERATOR_RECURSIVE_018

#ifdef TEST_ITERATOR_RECURSIVE_019
#endif // TEST_ITERATOR_RECURSIVE_019

#ifdef TEST_ITERATOR_RECURSIVE_020
#endif // TEST_ITERATOR_RECURSIVE_020

#ifdef TEST_ITERATOR_RECURSIVE_021
#endif // TEST_ITERATOR_RECURSIVE_021

#ifdef TEST_ITERATOR_RECURSIVE_022
#endif // TEST_ITERATOR_RECURSIVE_022

#ifdef TEST_ITERATOR_RECURSIVE_023
#endif // TEST_ITERATOR_RECURSIVE_023

#ifdef TEST_ITERATOR_RECURSIVE_024
#endif // TEST_ITERATOR_RECURSIVE_024

#ifdef TEST_ITERATOR_RECURSIVE_025
#endif // TEST_ITERATOR_RECURSIVE_025

#ifdef TEST_ITERATOR_RECURSIVE_026
#endif // TEST_ITERATOR_RECURSIVE_026

#ifdef TEST_ITERATOR_RECURSIVE_027
#endif // TEST_ITERATOR_RECURSIVE_027

#ifdef TEST_ITERATOR_RECURSIVE_028
#endif // TEST_ITERATOR_RECURSIVE_029

#ifdef TEST_ITERATOR_RECURSIVE_030
#endif // TEST_ITERATOR_RECURSIVE_030

#ifdef TEST_ITERATOR_RECURSIVE_031
#endif // TEST_ITERATOR_RECURSIVE_031

#ifdef TEST_ITERATOR_RECURSIVE_032
#endif // TEST_ITERATOR_RECURSIVE_032


#if defined(__GNUC__) || defined(__MINGW__) || defined(__MINGW32__)
    #pragma GCC diagnostic pop
#endif


#endif



